﻿using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UMLSynthesizer.CSharpAnalyzer.Helpers;
using UMLSynthesizer.LangAnalyzer;
using UMLSynthesizer.LangAnalyzer.Elements;
using UMLSynthesizer.LangAnalyzer.ExtensionMethods;

namespace UMLSynthesizer.CSharpAnalyzer.Elements
{
    class CSharpNamespaceElement : INamespaceElement
    {
        #region Fields

        IEnumerable<KeyValuePair<int, NamespaceDeclarationSyntax>> elementNodes;
        CSharpElementContainerHelper containerHelper;

        #endregion

        #region Constructor

        /// <summary>
        /// The constructor
        /// </summary>
        /// <param name="elementNodes">
        /// List of namespace nodes
        /// Key: The relative deep of this namespace definition inside node.
        /// Value: Nodes with this namespace declaration</param>
        /// <param name="parentElement">The parent container</param>
        public CSharpNamespaceElement(IEnumerable<KeyValuePair<int, NamespaceDeclarationSyntax>> elementNodes,
            IElementBase parentElement)
        {
            if (elementNodes == null)
                throw new ArgumentNullException("elementNodes");
            if (elementNodes.Count() == 0)
                throw new ArgumentException("elementNodes can't be empty");
            if (parentElement == null)
                throw new ArgumentNullException("parentElement");

            this.elementNodes = elementNodes;
            this.ParentElement = parentElement;
            this.ProjectOwner = parentElement.ProjectOwner;
            this.containerHelper = new CSharpElementContainerHelper(this,
                () => from node in elementNodes
                      where CalculatePathDeep(node.Value.Name.ToString()) == node.Key
                      select node.Value,
                () => from node in elementNodes
                      where CalculatePathDeep(node.Value.Name.ToString()) != node.Key
                      select new KeyValuePair<int, SyntaxNode>(node.Key, node.Value));

            this.MetricDictionary = new Dictionary<LanguageAnalyzer.Metrics, double>();
        }

        #endregion

        #region Properties

        public string Identifier
        {
            get
            {
                return elementNodes.First().Value.Name
                    .ToString().Split(new char[] { '.' }).ElementAt(elementNodes.First().Key);
            }
        }
        public ElementKinds Kind { get { return ElementKinds.Namespace; } }
        public IElementBase ParentElement { get; private set; }
        public IProjectElement ProjectOwner { get; private set; }

        public IEnumerable<IClassElement> ContainedClasses { get { return containerHelper.ContainedClasses; } }
        public IEnumerable<IDelegateElement> ContainedDelegates { get { return containerHelper.ContainedDelegates; } }
        public IEnumerable<IEnumElement> ContainedEnums { get { return containerHelper.ContainedEnums; } }
        public IEnumerable<IFieldElement> ContainedFields { get { return containerHelper.ContainedFields; } }
        public IEnumerable<IInterfaceElement> ContainedInterfaces { get { return containerHelper.ContainedInterfaces; } }
        public IEnumerable<IMethodElement> ContainedMethods { get { return containerHelper.ContainedMethods; } }
        public IEnumerable<INamespaceElement> ContainedNamespaces { get { return containerHelper.ContainedNamespaces; } }
        public IEnumerable<IPropertyElement> ContainedProperties { get { return containerHelper.ContainedProperties; } }
        public IEnumerable<IStructElement> ContainedStructs { get { return containerHelper.ContainedStructs; } }

        public Dictionary<LanguageAnalyzer.Metrics, double> MetricDictionary { get; private set; }

        #endregion

        #region Private helpers

        int CalculatePathDeep(string path) { return path.Split(new char[] { '.' }).Length - 1; }

        #endregion
    }
}
